#ifndef _NE_MATERIAL_H_
#define _NE_MATERIAL_H_

#include <graphics/Texture.h>
#include <graphics/GLSLProgram.h>

namespace ne
{
    class NEAPI Material : public Resource
    {
        public:
            Material(ResourceManager *pManager,
                     const uint64_t id,
                     const std::string &name,
                     const std::string &fileName,
                     const bool isManual,
                     ManualResourceLoader *pLoader);

            void setAmbient(const Color &a);
            Color getAmbient() const;
            void setDiffuse(const Color &a);
            Color getDiffuse() const;
            void setSpecular(const Color &a);
            Color getSpecular() const;
            void setEmission(const Color &a);
            Color getEmission() const;
            void setShininess(const real a);
            real getShininess() const;

            void setTransparent(const bool b);
            bool isTransparent() const;

            void setTransparentCutout(const bool b);
            bool isTransparentCutout() const;

            void setFogEnable(const bool b);
            bool isFogEnable() const;

            void setSelfIlluminated(const bool b);
            bool isSelfIlluminated() const;

            void setLightEnable(const bool b);
            bool isLightEnable() const;

            void setCastShadow(const bool b);
            bool isCastShadow() const;

            void setReceiveShadow(const bool b);
            bool isReceiveShadow() const;

            void setProgram(const GLSLProgramPtr &pProgram);
            GLSLProgramPtr getProgram() const;

            bool useProgram(const bool use);

            void setTexture(const std::string &name, const TexturePtr &pTexture);
            bool hasTexture(const std::string &name) const;
            TexturePtr getTexture(const std::string &name) const;
            bool removeTexture(const std::string &name);
            const TextureMap& getTextureMap() const;

            virtual ~Material();

        protected:
            virtual bool loadImplement();

            virtual bool unloadImplement();

            virtual bool downloadImplement();

            virtual size_t _calculateSize() const;

        private:
            Color mAmbient;
            Color mDiffuse;
            Color mSpecular;
            Color mEmission;
            real mShininess;    // [0.0f, 128.0f]

            bool mTransparent;
            bool mTransparentCutout;
            bool mFogEnable;
            bool mSelfIlluminated;
            bool mLightEnable;
            bool mCastShadow;
            bool mReceiveShadow;

            GLSLProgramPtr mpProgram;

            TextureMap mTextureMap;
    };

    class NEAPI MaterialPtr : public SharedPtr<Material>
    {
        public:
            MaterialPtr() : SharedPtr<Material>() {}
            explicit MaterialPtr(Material *pMaterial) : SharedPtr<Material>(pMaterial) {}
            MaterialPtr(const MaterialPtr &pMaterial) : SharedPtr<Material>(pMaterial) {}

            MaterialPtr(const ResourcePtr &p)
                : SharedPtr<Material>()
            {
                mpPtr = static_cast<Material*>(p.ptr());
                mpUseCount = p.getUseCountPtr();
                if (mpUseCount)
                {
                    ++(*mpUseCount);
                }
            }

            MaterialPtr& operator = (const ResourcePtr &p)
            {
                if (mpPtr == static_cast<Material*>(p.ptr()))
                {
                    return *this;
                }
                MaterialPtr temp(p);
                swap(temp);
                return *this;
            }
    };
}

#endif
